最近在本地调试、写 PHP 单元测试、动态 Mock 函数时,安装了 php-uopz 扩展后,代码直接报错:
Fatal error: Uncaught Error: Call to undefined function uopz_override()
很多人以为是扩展没装成功,其实 99% 原因是 Uopz 版本过高。本文带你彻底搞懂报错原因、新旧版本区别、完整可用写法、配置项、避坑指南。
一、报错根本原因
Uopz 在 7.0 版本做了毁灭性 API 重构:
✅ Uopz 6.x 及以下:支持传统函数
uopz_override()重写函数/方法uopz_set_return()劫持返回值uopz_delete()删除函数/常量
❌ Uopz 7.0+ 新版:彻底废弃以上所有旧函数
新版统一只用两个核心方法:
uopz_set_mock()设置模拟/重写uopz_unset_mock()恢复原生
二、先确认你的 Uopz 版本
执行命令查看版本:
php -r "echo phpversion('uopz');"
- 输出版本 7.x / 8.x:不支持旧写法,必须用新 API
- 无输出:扩展根本没加载成功
三、两种解决方案(任选其一)
方案一:适配新版 Uopz7+(推荐、长期使用)
放弃 uopz_override,全面改用 uopz_set_mock,兼容所有新版 PHP7.4~PHP8.3。
1. 重写系统函数(替代 uopz_override)
<?php
// 劫持原生 strlen 函数
uopz_set_mock('strlen', function ($str) {
return 999;
});
echo strlen('abc'); // 输出 999
// 恢复原生函数
uopz_unset_mock('strlen');
echo strlen('abc'); // 输出 3
2. 快速固定返回值(替代 uopz_set_return)
<?php
// 直接固定返回假数据,无需写闭包
uopz_set_mock('file_get_contents', 'fake remote data');
echo file_get_contents('https://www.baidu.com');
// 取消劫持
uopz_unset_mock('file_get_contents');
3. Mock 类方法
<?php
class Demo
{
public function hello()
{
return '原始结果';
}
}
// 重写类方法
uopz_set_mock(Demo::class . '::hello', function () {
return 'Uopz Mock 结果';
});
echo (new Demo())->hello(); // 输出 Mock 结果
// 恢复原生方法
uopz_unset_mock(Demo::class . '::hello');
方案二:降级 Uopz 继续使用旧写法(uopz_override)
如果你的旧代码大量依赖uopz_override,不想改代码,可以直接降级到 6.1.11(最后一个旧 API 稳定版)。
# 卸载现有新版
pecl uninstall uopz
# 安装兼容旧函数的最后版本
pecl install uopz-6.1.11
# 重启 PHP-FPM
systemctl restart php8.1-fpm
降级后即可正常使用 uopz_override / uopz_set_return / uopz_delete。
四、必须配置的 php.ini 权限(关键)
无论新版旧版,不开启权限会失效或报错无权限。
查看配置文件路径:
php --ini
编辑 php.ini 添加以下配置:
uopz.enable = On
uopz.allow_override = On
uopz.allow_delete = On
修改后重启服务:
# 根据你的PHP版本修改
systemctl restart php8.1-fpm
五、新版 Uopz7+ 完整对照表
| 旧版废弃函数 | 新版替代方案 |
|---|---|
| uopz_override() | uopz_set_mock() |
| uopz_set_return() | uopz_set_mock() |
| uopz_delete() | 无替代(新版禁止删除内核函数) |
| uopz_restore() | uopz_unset_mock() |
六、高频避坑总结
- CLI 和 FPM 是两套配置:命令行能用 ≠ 网页能用,必须重启 php-fpm
- ondrej/php 源默认安装 Uopz7+,默认无旧函数
- 生产环境绝对禁止开启 Uopz:可动态篡改内核函数,高危漏洞
- Uopz 仅用于:本地单元测试、接口 Mock、调试代码
七、安装验证命令
# 查看扩展是否加载
php -m | grep uopz
# 查看版本
php -r "echo phpversion('uopz');"
# 判断新版Mock函数是否可用
php -r "var_dump(function_exists('uopz_set_mock'));"
结语
uopz_override 报错不是安装失败,是版本迭代导致的 API 大变更。新项目直接用 uopz_set_mock 新标准,老项目直接降级 Uopz 6.1.11 即可快速解决。
正文完
可以使用微信扫码关注公众号(ID:xzluomor)